package it.sisiper.mysight;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

/**
 * Activity launched at startup, the one responsible for starting and stopping core activity
 * 
 * @author Federico Lancerin 1057505
 *
 */

public class MySight extends Activity {

	private LinearLayout wibdowlay = null;
	private SurfaceView preview = null;
	private Display display = null;
	private SharedPreferences pref = null;
	private int previewWidth;
	private int previewHeight;
	private Button stream = null;
	private Button settings = null;

	private int status;
	private final int STOPPED = 0;
	private final int STREAMING = 1;

	private Toast tryingToConnect = null;
	private Toast youreStreamingToast = null;
	private Toast failedToConnectToast = null;
	private Toast connectionTimedOutToast = null;
	private Timer timer;

	private SensorManager sm = null;
	private SensorEventListener sel = null;
	private float angle = 0;
	private int orientation = 0;

	private Previewer previewThread;
	private NetworkAndTime senderAndTimer;
	
	private PowerManager pwrmgr = null;
	private WakeLock lock = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_my_sight);

		status = STOPPED;
		
		pwrmgr = (PowerManager) getSystemService(this.POWER_SERVICE);
		lock = pwrmgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Service WakeLock");

		pref = PreferenceManager.getDefaultSharedPreferences(this);
		tryingToConnect = Toast.makeText(this, "Trying to connect to the server", Toast.LENGTH_SHORT);
		youreStreamingToast = Toast.makeText(this, "Can't access options while streaming", Toast.LENGTH_SHORT);
		failedToConnectToast = Toast.makeText(this, "Failed to connect to host server, please check your Internet connection and try again",
						Toast.LENGTH_LONG);
		connectionTimedOutToast = Toast.makeText(this, "Connection timed out, please check your Internet connection and try again",
						Toast.LENGTH_LONG);

		timer = new Timer();
		
		timer.schedule(new TimerTask() {			
			@Override
			public void run() {
				runOnUiThread(connectionTimeOutCheck);
			}
		}, 30000, 30000);
		
		
		
		sm = (SensorManager) getSystemService(this.SENSOR_SERVICE);
		sel = new SensorEventListener() {
			public void onSensorChanged(SensorEvent event) {
				angle = (10 * event.values[0]);
				if (angle > 45) {
					orientation = -1;
					if (senderAndTimer != null)
						senderAndTimer.setOrientation(orientation);
				} else if (angle < -45) {
					orientation = 1;
					if (senderAndTimer != null)
						senderAndTimer.setOrientation(orientation);
				} else {
					orientation = 0;
					if (senderAndTimer != null)
						senderAndTimer.setOrientation(orientation);
				}
			}

			public void onAccuracyChanged(Sensor sensor, int accuracy) {
			}
		};

		getBestPreviewSize();
		display = ((WindowManager) getSystemService(WINDOW_SERVICE))
				.getDefaultDisplay();
		wibdowlay = (LinearLayout) findViewById(R.id.wibdowLayout);

		preview = new SurfaceView(this);
		wibdowlay.addView(preview, previewWidth, previewHeight);
		stream = (Button) findViewById(R.id.startStream);
		settings = (Button) findViewById(R.id.settings);

		previewThread = new Previewer(preview);

		stream.setOnClickListener(streamStopButton);
		settings.setOnClickListener(optionButton);

		previewThread.start();
		previewThread.resumee();

		sm.registerListener(sel,
				sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_GAME);
	}

	private OnClickListener optionButton = new OnClickListener() {
		public void onClick(View v) {
			if (status == STOPPED) {
				Intent intent = new Intent(getApplicationContext(),
						OptionMenu.class);
				previewThread.pause();
				startActivity(intent);
			}
			if (status == STREAMING) {
				youreStreamingToast.show();
			}
		}
	};

	private OnClickListener streamStopButton = new OnClickListener() {
		public void onClick(View v) {
			if (status == STOPPED) {
				stream.setEnabled(false);
				status = STREAMING;
				tryingToConnect.show();
				senderAndTimer = new NetworkAndTime(previewThread);
				senderAndTimer.setServerAddress(pref.getString("serverAddress",
						null));
				senderAndTimer.setDelay(Integer.parseInt(pref.getString(
						"possibleDelay", "2")));
				senderAndTimer.start();
				timer.schedule(new TimerTask() {
					@Override
					public void run() {
						runOnUiThread(connectionCheck);
					}
				}, 5000);
			} else if (status == STREAMING) {
				if (lock.isHeld()) lock.release();
				senderAndTimer.setAcquisition(false);
				senderAndTimer.disconnectFromServer();
				senderAndTimer = null;
				status = STOPPED;
				stream.setBackgroundDrawable(getResources().getDrawable(R.drawable.streambutton));
				stream.setText("Stream");
			}
		}
	};

	private TimerTask connectionCheck = new TimerTask() {
		@Override
		public void run() {
			if (senderAndTimer.isConnected()) {
				lock.acquire();
				senderAndTimer.setAcquisition(true);
				stream.setBackgroundDrawable(getResources().getDrawable(R.drawable.stopbutton));
				stream.setText("Stop");
			} else {
				status = STOPPED;
				senderAndTimer = null;
				failedToConnectToast.show();
			}
			stream.setEnabled(true);
		}
	};

	private TimerTask connectionTimeOutCheck = new TimerTask() {
		@Override
		public void run() {
			if (status == STREAMING) {
				System.out.println("Checking Socket..");
				if (!senderAndTimer.isConnected()) {
					if (lock.isHeld()) lock.release();
					System.out.println("Socket down, closing connection and going home now.");
					senderAndTimer.setAcquisition(false);
					senderAndTimer.disconnectFromServer();
					senderAndTimer = null;
					status = STOPPED;
					stream.setBackgroundDrawable(getResources().getDrawable(R.drawable.streambutton));
					stream.setText("Stream");
					connectionTimedOutToast.show();
				} else System.out.println("Socket alright.");
			}
		}
	};

	@Override
	public void onResume() {
		super.onResume();
		previewThread.resumee();
	}

	@Override
	public void onPause() {
		super.onPause();
	}

	@Override
	public void onDestroy() {
		timer.cancel();
		timer.purge();
		if (lock.isHeld()) lock.release();
		if (senderAndTimer != null)
			senderAndTimer.disconnectFromServer();
		previewThread.pause();
		sm.unregisterListener(sel);
		previewThread.interrupt();
		super.onDestroy();
	}

	private void getBestPreviewSize() {
		DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);

		Point size = new Point();
		size.x = metrics.widthPixels;
		size.y = metrics.heightPixels;

		size.y = (int) (size.y - (size.y / 10));
		size.x = (size.x - 20);

		if (size.x / size.y < 0.75)
			size.y = (int) (size.x / 0.75);
		else
			size.x = (int) (size.y * 0.75);

		previewWidth = size.x;
		previewHeight = size.y;

		System.out.println("proposed width = " + size.x + " and height = "
				+ size.y);
	}

	public class Previewer extends Thread {

		private SurfaceView surface = null;
		private SurfaceHolder previewHolder = null;
		private Camera camera = null;

		Bitmap img = null;
		Bitmap rotatedImg = null;
//		Matrix matrix90 = new Matrix();
//		Matrix matrix180 = new Matrix();

		private boolean inPreview = false;
		private boolean cameraConfigured = false;

		public Previewer(SurfaceView toWorkOn) {
			surface = toWorkOn;
//			matrix90.setRotate(90f);
//			matrix180.setRotate(180f);
		}

		public void run() {
			previewHolder = surface.getHolder();
			previewHolder.addCallback(surfaceCallback);
			previewHolder.setSizeFromLayout();
			previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}

		public void pause() {
			if (inPreview) {
				camera.stopPreview();
			}
			camera.release();
			camera = null;
			inPreview = false;
		}

		public void resumee() {
			if (camera == null) camera = Camera.open();
			startPreview();
		}

		public void takePic() {
			camera.setOneShotPreviewCallback(cb);
		}

		Camera.PreviewCallback cb = new PreviewCallback() {
			public void onPreviewFrame(byte[] data, Camera camera) {
				if (data != null) {
					senderAndTimer.sendPhoto(data);
				}
			}
		};

		private void initPreview(int width, int height) {
			if (camera != null && previewHolder.getSurface() != null) {
				try {
					camera.setPreviewDisplay(previewHolder);
				} catch (Throwable t) {
					t.printStackTrace();
				}
				Camera.Parameters parameters = camera.getParameters();
				parameters.setPreviewSize(640, 480);
				parameters.setPreviewFormat(ImageFormat.NV21);
				camera.setParameters(parameters);
				cameraConfigured = true;
			}
		}

		private void startPreview() {
			if (cameraConfigured && camera != null) {
				camera.startPreview();
				inPreview = true;
			}
		}

		SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
			public void surfaceCreated(SurfaceHolder holder) {
			}

			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
				camera.stopPreview();
				camera.setDisplayOrientation(90);
				initPreview(640, 480);
				startPreview();
			}

			public void surfaceDestroyed(SurfaceHolder holder) {
			}
		};

	}
}